home *** CD-ROM | disk | FTP | other *** search
/ Young Minds / Young Minds Interactive CD-ROM.ISO / sdi / missile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-06-18  |  7.6 KB  |  301 lines

  1. /**********************************  missile.c  ***********************/
  2. #include <pixrect/pixrect_hs.h>
  3. #include <sunwindow/notify.h>
  4. #include "sdi.h"
  5.  
  6. /*
  7.  * Copyright 1987 by Mark Weiser.
  8.  * Permission to reproduce and use in any manner whatsoever on Suns is granted
  9.  * so long as this copyright and other identifying marks of authorship
  10.  * in the code and the game remain intact and visible.  Use of this code
  11.  * in other products is reserved to me--I'm working on Mac and IBM versions.
  12.  */
  13.  
  14. /*
  15.  * Code to start and update missiles lives here, including missiles
  16.  * traveling between the two windows.  Launching of missiles
  17.  * is done in incoming.c.
  18.  */
  19.  
  20. static struct missile *m_head = NULL;
  21. static Notify_value ballistic_timer();
  22.  
  23. /*
  24.  * Throw a missile onto a window. Only x is suppied, because direction
  25.  * determines whether the missile starts at the top or bottom of the window.
  26.  * Speed is in units of approximate pixels-per-timestep.  Direction
  27.  * should be UP or DOWN, which are defined in sdi.h
  28.  */
  29. start_missile(x, direction, speed, pw)
  30. int x, direction, speed;
  31. Pixwin *pw;
  32. {
  33.     struct missile *mid = (struct missile *)malloc(sizeof(struct missile));
  34.     int ratio, number_of_steps;
  35.     int final_x = (random() % (max_x - MARGIN)) + (MARGIN/2);
  36.  
  37.     panel_set_value(foe_item, panel_get_value(foe_item) + 1);
  38.  
  39.     mid->start_x = mid->x = x;
  40.     mid->speed = speed;
  41.     mid->refs = 1;
  42.     mid->destroyed = FALSE;
  43.  
  44.     number_of_steps = max(1,(ABS(final_x - mid->start_x) + max_y)/speed);
  45.     mid->inc_x = (final_x - mid->start_x)/number_of_steps;
  46.     mid->inc_y = max_y/number_of_steps;
  47.     if (mid->inc_y < 1) {
  48.         mid->inc_y += 1;
  49.         mid->inc_x -= 1;
  50.     }
  51.  
  52.     
  53.     /* I'm making this up as I go... */
  54.     {
  55.         double desired = (double)(ABS(final_x - mid->start_x)/(double)max_y);
  56.         double actual = (double)ABS(mid->inc_x)/(double)ABS(mid->inc_y);
  57.         mid->slip = (double)1.0 / (desired - actual);
  58.         mid->slip_cnt = 0;        
  59.     } 
  60.  
  61.     if (direction == DOWN) {
  62.         mid->start_y = mid->y = 0;
  63.     } else {
  64.         mid->start_y = mid->y = max_y;
  65.         mid->inc_y = -mid->inc_y;
  66.     }
  67.     mid->pw = pw;
  68.             
  69.     inc_missile(mid);
  70.  
  71.     missile_count++;
  72.     mid->next = m_head;
  73.     m_head = mid;
  74. }
  75.  
  76. /*
  77.  * Move a missile ahead and see if hits anything.
  78.  * Helper routine passed into doto_missiles.
  79.  */
  80. update_missile(mid)
  81. struct missile *mid;
  82. {
  83.     inc_missile(mid);
  84.     if (intersect(mid)) {
  85.         start_blast(mid->x, mid->y, 0, 0, mid->pw, blastkillcircles);
  86.         destroy_missile(mid);
  87.         if (mid->pw == citypw)
  88.             bump_score(foe_value/5);
  89.         else bump_score(foe_value);
  90.     } else if (mid->inc_y > 0 && mid->y >= max_y-burst_distance) {
  91.         start_blast(mid->x, mid->y - 10, 0, 0, mid->pw, citykillcircles);
  92.         destroy_missile(mid);
  93.     } else if (mid->inc_y < 0 && mid->y <= 0) {
  94.         start_ballistic(mid->x, mid->speed);
  95.         destroy_missile(mid);
  96.     } else if (mid->x < 0 || mid->x > max_x) {
  97.         start_blast(mid->x, mid->y, 0, 0, mid->pw, blastkillcircles);
  98.         destroy_missile(mid);
  99.     }
  100.     return 0;
  101. }
  102.  
  103. /*
  104.  * Update the missile track.
  105.  */
  106. inc_missile(mid)
  107. struct missile *mid;
  108. {
  109.     /* Compute basic update */
  110.     mid->old_x = mid->x;
  111.     mid->old_y = mid->y;
  112.     mid->x += mid->inc_x;
  113.     mid->y += mid->inc_y;
  114.  
  115.     /* Adjust skew for straighter lines */
  116.     if (mid->slip && ++mid->slip_cnt >= ABS(mid->slip)) {
  117.         mid->slip_cnt = 0;
  118.         if (mid->slip > 0) {
  119.             mid->x += 1;
  120.         } else {
  121.             mid->y += 1;
  122.         }
  123.     }
  124.  
  125.     /* Draw missile trail */
  126.     pw_vector(mid->pw, mid->old_x-1, mid->old_y, mid->x-1, mid->y, PIX_SRC, 1);
  127.     pw_vector(mid->pw, mid->old_x, mid->old_y, mid->x, mid->y, PIX_SRC, 1);
  128.     pw_vector(mid->pw, mid->old_x+1, mid->old_y, mid->x+1, mid->y, PIX_SRC, 1);
  129. }
  130.  
  131. /*
  132.  * Get rid of a missile by erasing its track, removing it from
  133.  * the missile display list, and freeing its structure.  Explosion
  134.  * of the missile is the responsibility of the caller.
  135.  */
  136. destroy_missile(mid)
  137. struct missile *mid;
  138. {
  139.     char buff[128];
  140.     struct rect r;
  141.  
  142.     if (!mid->destroyed) {
  143.         panel_set_value(foe_item, panel_get_value(foe_item) - 1);
  144.         sprintf(buff, "%d", atol(panel_get_value(total_foe_item))+1);
  145.         panel_set_value(total_foe_item, buff);
  146.         mid->destroyed = TRUE;
  147.         pw_vector(mid->pw, mid->start_x - 2, mid->start_y,
  148.             mid->x - 2, mid->y,
  149.             PIX_NOT(PIX_SRC), 1);
  150.         pw_vector(mid->pw, mid->start_x - 1, mid->start_y,
  151.             mid->x - 1, mid->y,
  152.             PIX_NOT(PIX_SRC), 1);
  153.         pw_vector(mid->pw, mid->start_x, mid->start_y,
  154.             mid->x, mid->y,
  155.             PIX_NOT(PIX_SRC), 1);
  156.         pw_vector(mid->pw, mid->start_x + 1, mid->start_y,
  157.             mid->x + 1, mid->y,
  158.             PIX_NOT(PIX_SRC), 1);
  159.         pw_vector(mid->pw, mid->start_x + 2, mid->start_y,
  160.             mid->x + 2, mid->y,
  161.             PIX_NOT(PIX_SRC), 1);
  162.     
  163.         if (m_head == mid) {
  164.             m_head = mid->next;
  165.         } else {
  166.             struct missile *tmpmid = m_head;
  167.             while (tmpmid != NULL && tmpmid->next != mid) 
  168.                 tmpmid = tmpmid->next;
  169.             if (tmpmid != NULL)
  170.                 tmpmid->next = mid->next;
  171.         }
  172.         missile_count--;
  173.     }
  174.     if (--mid->refs == 0) {
  175.         free(mid);
  176.     }
  177. }
  178.  
  179. /*
  180.  * Update the score by 'inc', augmented by skill level.
  181.  */
  182. bump_score(inc)
  183. {
  184.     int score, skill;
  185.     float skill_multiplier;
  186.     char buf[128];
  187.     skill = (int)panel_get_value(skill_item);
  188.     switch (skill) {
  189.         case 0: skill_multiplier = 1.0; break;
  190.         case 1: skill_multiplier = 1.5; break;
  191.         case 2: skill_multiplier = 3; break;
  192.     }
  193.     score = atol(panel_get_value(score_item)) + (int)(((float)inc)*skill_multiplier);
  194.     sprintf(buf,"%d", score);
  195.     panel_set_value(score_item, buf);
  196. }
  197.  
  198. /*
  199.  * Call 'func' for missiles in the display list.  If func
  200.  * returns non-zero, stop.  Search the missiles round-robin,
  201.  * so we don't always find the same ones.
  202.  */
  203. doto_missiles(func)
  204. int (*func)();
  205. {
  206.     struct missile *ptr = m_head, *next;
  207.     while (ptr != NULL) {
  208.         next = ptr->next; /* in case 'func' destroys the missile */
  209.         (*func)(ptr);
  210.         ptr = next;
  211.     }
  212. }
  213.  
  214. /*
  215.  * Track a missile when traveling between windows.
  216.  */
  217. struct ballistic_type {int x, speed};
  218. start_ballistic(x, speed)
  219. {
  220.     extern int ballistic_delay;
  221.     struct itimerval timer;
  222.     struct ballistic_type *xptr = (struct ballistic_type *)calloc(1,sizeof(struct ballistic_type));
  223.     int old_value = (int)panel_get_value(ballistic_item);
  224.     xptr->x = x;
  225.     xptr->speed = speed;
  226.     panel_set_value(ballistic_item, old_value + 1);
  227.     
  228.     if (old_value == 0) {
  229.         ballistic_warning();
  230.     }
  231.     timer.it_interval.tv_usec = 0;
  232.     timer.it_interval.tv_sec = 0;
  233.     timer.it_value.tv_usec = 0;
  234.     timer.it_value.tv_sec = ballistic_delay;
  235.     if (timer.it_value.tv_sec > 0) {
  236.         notify_set_itimer_func(xptr, ballistic_timer, ITIMER_REAL, &timer, NULL);
  237.     } else {
  238.         ballistic_timer(xptr, NULL);
  239.     }
  240. }
  241.  
  242. /*
  243.  * Called when the between-window flight time of a missile is up.
  244.  */
  245. static Notify_value
  246. ballistic_timer(xptr, which)
  247. struct ballistic_type *xptr;
  248. int which;
  249. {
  250.     extern int ballistic_delay;
  251.     int val;
  252.     if (running) {
  253.         if (suspended) {
  254.             /* by rechecking at each in-flight interval for each missile, we
  255.                approximate remembering when the real relaunch rate.
  256.             */
  257.             suspendor(ballistic_timer, xptr, which, ballistic_delay);
  258.             return NOTIFY_DONE;
  259.         } else {
  260.             val = (int)panel_get_value(ballistic_item);
  261.             if (val > 0) {
  262.                 /* Three new missiles appear. */
  263.                 start_missile(xptr->x, DOWN, xptr->speed, citypw);
  264.                 start_missile(xptr->x, DOWN, xptr->speed, citypw);
  265.                 start_missile(xptr->x, DOWN, xptr->speed, citypw);
  266.                 panel_set_value(ballistic_item, panel_get_value(ballistic_item)-1);
  267.             }
  268.         }
  269.     }
  270.     free(xptr);
  271.     return NOTIFY_DONE;
  272. }
  273.  
  274. /*
  275.  * Just what it says.
  276.  */
  277. free_all_missiles()
  278. {
  279.     free_foe();
  280.     panel_set_value(ballistic_item, 0);
  281.     while(m_head != NULL)
  282.         destroy_missile(m_head);
  283. }
  284.  
  285. do_warn_bell()
  286. {
  287.     struct timeval tv;
  288.     tv.tv_sec = 0;
  289.     tv.tv_usec = 20000;    /* very short bell */
  290.     win_bell(window_get(cityframe, WIN_FD), tv, 0);
  291. }
  292.  
  293. #define WARN_INTERVAL 100000
  294.  
  295. ballistic_warning()
  296. {
  297.     do_with_delay(do_warn_bell, 0, WARN_INTERVAL);
  298.     do_with_delay(do_warn_bell, 0, 2*WARN_INTERVAL);
  299.     do_with_delay(do_warn_bell, 0, 3*WARN_INTERVAL);
  300. }
  301.